/* $Id$ */
/* vim: set filetype=verilog ts=8 sw=4 tw=132: */
/*****************************************************************************
 
              (c) Copyright 1987 - 2012,  VIA Technologies, Inc.       
                            ALL RIGHTS RESERVED                            
                                                                     
 This design and all of its related documentation constitutes valuable and
 confidential property of VIA Technologies, Inc.  No part of it may be
 reproduced in any form or by any means   used to make any transformation
 / adaptation / redistribution without the prior written permission from the
 copyright holders. 
 
------------------------------------------------------------------------------

  DESCRIPTION:

  FEATURES:

  TODO:

  AUTHORS:
     Shawn Fang
    
------------------------------------------------------------------------------
                             REVISION HISTORY
    $Log$

*****************************************************************************/
module fetch(
	output [31:0] pc,
	output [3:0] icode,
	output [3:0] ifun,
	output [3:0] rA,
	output [3:0] rB,
	output [31:0] valC,
	output reg [31:0] valP,
	output instrErr,

	input  clock,
	input  reset,
	input  [47:0] instr,
	input  [31:0] valM,
	input  i_ok,
	input  cnd);

wire   need_regids;
wire   need_valC;
wire   instr_valid;
reg [31:0] newpc;

regPC U_regPC
    (//outputs
    .pc(pc),
    //inputs
    .clock(clock),
    .reset(reset),
    .newpc(newpc));
assign icode=i_ok ? instr[7:4] : `INOP;
assign ifun=i_ok ? instr[3:0] : 4'h0;
assign rA=need_regids?instr[15:12]:4'h0;
assign rB=need_regids?instr[11:8]:4'h0;
assign valC=need_regids?instr[47:16]:instr[39:8];
always @ (icode or valC or valM or valP)
begin
    case(icode)
	`ICALL:newpc<=valC;
	`IJXX:newpc<=cnd?valC:valP;
	`IRET:newpc<=valM;
	`IHALT:newpc<=newpc;
	default:newpc<=valP;
    endcase
end

always @ (need_regids or need_valC or pc)
begin
    case({need_regids,need_valC})
    2'b00:valP<=pc+1;
    2'b01:valP<=pc+5;
    2'b10:valP<=pc+2;
    2'b11:valP<=pc+6;
    default:valP<=pc;
    endcase
end
assign need_regids=(icode==`IRRMOVL
		||icode==`IOPL
		||icode==`IPUSHL
		||icode==`IPOPL
		||icode==`IIRMOVL
		||icode==`IRMMOVL
		||icode==`IMRMOVL)?1'b1:1'b0;
assign instr_valid=(icode==`INOP
		||icode==`IHALT
		||(icode==`IRRMOVL && ifun<=4'h6)
		||icode==`IIRMOVL
		||icode==`IRMMOVL
		||icode==`IMRMOVL
		||(icode==`IOPL && ifun<=4'h3)
		||(icode==`IJXX && ifun<=4'h6)
		||icode==`ICALL
		||icode==`IRET
		||icode==`IPUSHL
		||icode==`IPOPL)?1'b1:1'b0;
assign instrErr=~instr_valid || ~i_ok;
assign need_valC=(icode==`IIRMOVL
		||icode==`IRMMOVL
		||icode==`IMRMOVL
		||icode==`IJXX
		||icode==`ICALL)?1'b1:1'b0;
endmodule

